package com.xinxin.blockchain.api.interceptor;

import com.xinxin.base.entity.Claim;
import com.xinxin.base.entity.ResultCode;
import com.xinxin.base.enums.TokenTypeEnum;
import com.xinxin.base.holder.ThreadLocalContextHolder;
import com.xinxin.base.service.ITokenService;
import com.xinxin.base.util.JsonUtil;
import com.xinxin.blockchain.constant.ErrorCode;
import com.xinxin.blockchain.service.IMemberService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class AuthInterceptor implements HandlerInterceptor {

    private final ThreadLocalContextHolder<Long> threadLocalContextHolder;

    @Autowired
    private ITokenService tokenService;

    @Autowired
    private IMemberService memberService;

    public AuthInterceptor(ThreadLocalContextHolder<Long> threadLocalContextHolder) {
        this.threadLocalContextHolder = threadLocalContextHolder;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requestHeaders = request.getHeader("Access-Control-Request-Headers");
        requestHeaders = StringUtils.isBlank(requestHeaders) ? "" : (", " + requestHeaders);
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Methods", "GET, POST");
        response.setHeader("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, X-Requested-With" + requestHeaders);
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Max-Age", "3600");

        if (!(handler instanceof HandlerMethod) && request.getMethod().equals(RequestMethod.OPTIONS.name())) {
            return true;
        }

        String token = (String) request.getAttribute("key");
        if (StringUtils.isBlank(token)) {
            response(response, ErrorCode.UNAUTHORIZED);
            return false;
        }

        Claim claim = tokenService.validClaim(TokenTypeEnum.AUTHORIZATION, token);
        Long accountId = claim.getAccountId();

        String secret = memberService.getAccountSecret(accountId);
        if (StringUtils.isBlank(secret)) {
            response(response, ErrorCode.UNAUTHORIZED);
            return false;
        }

        String signature = tokenService.signature(claim.getPayload(), secret);
        if (!signature.equals(claim.getSignature())) {
            response(response, ErrorCode.UNAUTHORIZED);
            return false;
        }

        threadLocalContextHolder.setContext(accountId);

        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        threadLocalContextHolder.clean();
    }

    private void response(HttpServletResponse response, ResultCode resultCode) throws IOException {
        // response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");

        PrintWriter writer = response.getWriter();
        writer.print(JsonUtil.writeValueAsString(resultCode));
        writer.flush();
    }
}
